package robot

import (
	"context"
	"encoding/base64"
	"strconv"
	"time"

	"device-admin/internal/app/grpc/protoc/robotc"
	"device-admin/internal/app/grpc/service/pubsub"
	"device-admin/internal/app/web/service/cmd"
	"device-admin/internal/models"

	"device-admin/config/mysql"
	"device-admin/config/redis"
	"device-admin/internal/define"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"google.golang.org/protobuf/proto"
)

// wildmsgCMDPack wilgmsg命令fengzhuang
func wildmsgCMDPack(robotID string, msgType string, msgContent []byte) (msgID string, err error) {
	if robotID == "" {
		return "", errorx.New("设备id不能为空", -1)
	}
	wm := &robotc.WildMsg{}
	wm.FromType = robotc.WildMsg_eMobileServiceClient
	wm.FromID = "server"
	wm.ToType = robotc.WildMsg_eMonitorClient
	wm.ToID = "95"
	wm.BodyType = msgType
	wm.BodyContent = msgContent
	// 必须加上前缀，否则不会发布下发的结果
	wm.StrGUID = "waitmsg_" + helper.RandString(16)
	// protobuf序列化
	bytes, err := proto.Marshal(wm)
	if err != nil {
		logx.Error(context.Background(), "WildmsgCMDPackErr", logx.Err(err))
		return "", err
	}
	// 通过redis发布指令，待连接会话订阅
	logx.Info(context.Background(), "WildmsgCMDPublish-"+msgType, logx.String("robot_id", robotID))
	err = pubsub.CMDPublish(robotID, "95", "wildmsg", base64.StdEncoding.EncodeToString(bytes))
	if err != nil {
		return wm.StrGUID, errorx.New("命令发布失败", -1)
	}
	return wm.StrGUID, nil
}

// WildmsgStartTask 开始任务
func WildmsgStartTask(robotID string, mapName string, taskName string, runCount int, username string) error {
	cmd := &robotc.StartTaskCMD{}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	cmd.NrunCount = int32(runCount)
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgContinueTask 继续任务
func WildmsgContinueTask(robotID string, username string) error {
	cmd := &robotc.ResumeTaskCMD{}
	cmd.StrResver = []byte("")
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgPauseTask 暂停任务
func WildmsgPauseTask(robotID string, taskID string, username string) error {
	cmd := &robotc.PauseCurrentTaskCMD{}
	cmd.StrTaskId = []byte(taskID)
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgEndTask 终止任务
func WildmsgEndTask(robotID string, _ string, _ string) error {
	cmd := &robotc.ReqCmdEndActionMode{}
	cmd.BEndTaskRun = true
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgAutoRelocation 自动重定位
func WildmsgAutoRelocation(robotID string, _ string) error {
	var device models.Device
	// 判断id不能为空
	if robotID == "" {
		return errorx.New("设备id不能为空", -1)
	}
	// 获取设备正在使用的地图
	rowsAffected := mysql.NewDB().Model(&models.Device{}).
		Where("robot_id = ?", robotID).
		Take(&device).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("无效的设备id", -1)
	}
	currentMapName := device.CurrentMapName
	// 设置wildmsg内容
	reqCmdReloc := &robotc.ReqCmdReloc{}
	reqCmdReloc.Type = robotc.ECmdRelocType_eCmdRelocTypePos
	reqCmdReloc.RouteName = []byte(currentMapName)
	msgType := string(reqCmdReloc.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(reqCmdReloc)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgManualRelocation 手动重定位
func WildmsgManualRelocation(robotID string, posX, posY, posTh float64, _ string) error {
	var device models.Device
	// 判断id不能为空
	if robotID == "" {
		return errorx.New("设备id不能为空", -1)
	}
	// 获取设备正在使用的地图
	rowsAffected := mysql.NewDB().Model(&models.Device{}).
		Where("robot_id = ?", robotID).
		Take(&device).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("无效的设备id", -1)
	}
	currentMapName := device.CurrentMapName
	// 设置wildmsg内容
	reqCmdReloc := &robotc.ReqCmdReloc{}
	reqCmdReloc.PosX0 = float32(posX)
	reqCmdReloc.PosY0 = float32(posY)
	reqCmdReloc.PosTh0 = float32(posTh)
	reqCmdReloc.Type = robotc.ECmdRelocType_eCmdRelocTypePos
	reqCmdReloc.RouteName = []byte(currentMapName)
	msgType := string(reqCmdReloc.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(reqCmdReloc)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgModifyTaskTime 修改任务时段
func WildmsgModifyTaskTime(
	robotID string,
	mapName string,
	taskName string,
	startHour int, startMin int,
	endHour int, endMin int,
	username string,
) error {
	cmd := &robotc.ModifyWorkingTimeCMD{
		ExData: &robotc.CmdExtend{},
	}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	cmd.NStartHour = int32(startHour)
	cmd.NStartMin = int32(startMin)
	cmd.NEndHour = int32(endHour)
	cmd.NEndMin = int32(endMin)
	cmd.ExData.LlTimeStamp = time.Now().UnixMilli()
	cmd.ExData.StrUserName = []byte(username)
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgModifyTaskTimes 修改任务次数
func WildmsgModifyTaskTimes(robotID string, mapName string, taskName string, runCount int, username string) error {
	cmd := &robotc.ModifyWorkingTimesCMD{
		ExData: &robotc.CmdExtend{},
	}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	cmd.NRunCount = int32(runCount)
	cmd.ExData.LlTimeStamp = time.Now().UnixMilli()
	cmd.ExData.StrUserName = []byte(username)
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// 恢复任务
func WildmsgResumeTask(robotID string, mapName string, taskName string, taskEffection string) error {
	cmd := &robotc.TaskEffectivenessCMD{}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	cmd.StrTaskEffection = []byte(taskEffection)
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// 恢复异常任务
func WildmsgResumeExceptionTask(robotID string, username string, exceptionType string) error {
	cmd := &robotc.ResumeTaskCMD{}
	cmd.StrResver = []byte(exceptionType)
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// 关机
func WildmsgShutdown(robotID string, username string) error {
	cmd := &robotc.ShutdownCMD{}
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgCharge 充电
func WildmsgCharge(robotID string, _ string) error {
	// 充电模式设置
	cmd := &robotc.ReqCmdStartActionMode{}
	cmd.Mode = robotc.ECmdActionMode_eReCharging
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// RemoteReboot 远程排障
func WildmsgRemoteReboot(robotID string, cmpType int, opt ...int) error {
	cmd := &robotc.ReqDeviceOptSet{}
	cmd.Device = int32(cmpType) // 设备类型
	if len(opt) > 0 {
		cmd.Opt = int32(opt[0])
	}
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgTaskOver 人工接管
func WildmsgTaskOver(robotID string, status int, username string) error {
	takeOverCMD := &robotc.TakeOverCMD{
		NTakeOverStatus: int32(status),
		ExData:          &robotc.CmdExtend{},
	}
	takeOverCMD.ExData.LlTimeStamp = time.Now().UnixMilli()
	takeOverCMD.ExData.StrUserName = []byte(username)
	msgType := string(takeOverCMD.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(takeOverCMD)
	if err == nil {
		msgID, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
		// 等待命令执行结果
		resData, err := cmd.WaitCmdRsp(robotID, "wildmsg", msgID, "95")
		if err != nil {
			return err
		}
		// 解析响应的内容
		takseOverRsp := &robotc.RspTakeOver2ClientC2S{}
		if err := proto.Unmarshal(resData, takseOverRsp); err == nil {
			resCode := int(takseOverRsp.EnStatus)
			if resCode == 0 {
				return errorx.New("未知错误", -1)
			} else if resCode == 1 {
				return nil
			} else if resCode == 2 {
				return errorx.New("接管失败", -1)
			}
		}
	}
	return err
}

// WildmsgClosePushFlow 关闭推流
func WildmsgClosePushFlow(robotID string, username string) error {
	cmd := &robotc.PushFlowCMD{}
	cmd.NPushStatus = 0
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgPushFlow 推拉流
func WildmsgPushFlow(robotID string, username string, camType int) error {
	cmd := &robotc.PushFlowCMD{}
	cmd.NPushStatus = 1
	cmd.CamType = int32(camType)
	// 回充的推流地址
	if camType == 1 {
		cmd.Streamaddr = "rtmp://101.37.124.215:1985/myapp/" + robotID + "charging"
		// 深度相机推流地址
	} else if camType == 2 {
		cmd.Streamaddr = "rtmp://101.37.124.215:1985/myapp/" + robotID + "rgbd"
	}
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
		defer redisCtxCancel()
		// 标记推流标志(定期保活)
		redis.NewDB().Set(redisCtx, define.RedisISUnderMonitoring+robotID+":"+strconv.Itoa(camType), time.Now().Unix(), time.Second*2)
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
		// 标记正在推流
		redis.NewDB().HSet(redisCtx, define.RedisRobotRTInfo+robotID, define.IsPushingFlow+"-"+strconv.Itoa(camType), 1)
	}
	return err
}

// WildmsgSetRunningMap 设置地图
func WildmsgSetRunningMap(robotID string, mapName string, username string) error {
	setRuningMapCMD := &robotc.SetRuningMapCMD{
		StrMapName: []byte(mapName),
	}
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	setRuningMapCMD.ExData = exData
	msgType := string(setRuningMapCMD.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(setRuningMapCMD)
	if err == nil {
		msgID, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
		// 等待命令执行结果
		resData, err := cmd.WaitCmdRsp(robotID, "wildmsg", msgID, "95")
		if err != nil {
			return err
		}
		// 解析响应的内容
		setRuningMapRsp := &robotc.RspSetRuningMap2ClientC2S{}
		if err := proto.Unmarshal(resData, setRuningMapRsp); err == nil {
			resCode := int(setRuningMapRsp.GetEnStatus())
			if resCode == 0 {
				return errorx.New("未知错误", -1)
			} else if resCode == 1 {
				return nil
			} else if resCode == 2 {
				return errorx.New("地图已经在使用", -1)
			}
		}
	}
	return err
}

// WildmsgDeleteMap 删除任务 WildmsgDeleteTask
func WildmsgDeleteTask(robotID string, mapName string, taskName string, username string) error {
	cmd := &robotc.DeleteTaskCMD{}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgDeleteMap 删除地图
func WildmsgDeleteMap(robotID string, mapName string, username string) error {
	cmd := &robotc.DeleteMapCMD{}
	cmd.StrMapName = []byte(mapName)
	// 扩展信息
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgNotifyPrimitivePointCloud 通知推送
func WildmsgNotifyPrimitivePointCloud(robotID string, enable bool) error {
	cmd := &robotc.ReqNotifyPrimitivePointCloud{}
	cmd.BIsgetPrimitivePointCloud = enable
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
		redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
		defer redisCtxCancel()
		redis.NewDB().HSet(redisCtx, define.RedisRobotRTInfo+robotID, define.IsPushingPointCloud, 1)
	}
	return err
}

// 进入采集模式
func WildmsgSetCollectMode2Client(robotID string, mapName string, username string) error {
	cmd := &robotc.CollectModeCMD{}
	cmd.StrMapName = mapName
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// 采集完成
func WildmsgCollectModeFinish(robotID string, username string) error {
	cmd := &robotc.CollectModeFinishCMD{}
	cmd.BFinish = true
	// 额外数据
	exData := &robotc.CmdExtend{}
	exData.LlTimeStamp = time.Now().UnixMilli()
	exData.StrUserName = []byte(username)
	cmd.ExData = exData
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgTaskEffectivenessCMD 修改任务的有效性
func WildmsgTaskEffectivenessCMD(robotID string, mapName string, taskName string, taskEffection string) error {
	cmd := &robotc.TaskEffectivenessCMD{}
	cmd.StrMapName = []byte(mapName)
	cmd.StrTaskName = []byte(taskName)
	cmd.StrTaskEffection = []byte(taskEffection)
	msgType := string(cmd.ProtoReflect().Descriptor().FullName())
	msgContent, err := proto.Marshal(cmd)
	if err == nil {
		_, err := wildmsgCMDPack(robotID, msgType, msgContent)
		if err != nil {
			return err
		}
	}
	return err
}

// WildmsgSetDeviceOpt 远程重启/排障命令封装
// 需要通过wildmsg下发
// cmpType 重启类型
// 定义: 整机重启-,4G路由器重启,屏幕重启-
func WildmsgSetDeviceOpt(robotID string, cmpType int, opt ...int) error {
	deviceOPtSet := &robotc.ReqDeviceOptSet{}
	deviceOPtSet.Device = int32(cmpType) // 设备类型
	if len(opt) > 0 {
		deviceOPtSet.Opt = int32(opt[0])
	}
	wm := &robotc.WildMsg{}
	wm.FromType = robotc.WildMsg_eMobileServiceClient
	wm.FromID = "server"
	wm.ToType = robotc.WildMsg_eMonitorClient
	wm.ToID = "95"
	wm.BodyType = string(deviceOPtSet.ProtoReflect().Descriptor().FullName())
	var err error
	wm.BodyContent, err = proto.Marshal(deviceOPtSet)
	if err != nil {
		logx.Error(context.Background(), "RemoteRebootCMDPack", logx.Err(err))
	}
	wm.StrGUID = helper.RandString(16)
	bytes, err := proto.Marshal(wm)
	if err != nil {
		logx.Error(context.Background(), "RemoteRebootCMDPack", logx.Err(err))
		return err
	}
	// 发布
	err = pubsub.CMDPublish(robotID, "95", "wildmsg", base64.StdEncoding.EncodeToString(bytes))
	return err
}
